const { A, F } = { A: {}, F: {} }; // 基类扩展(对象、数组、方法)
F.is = (fn) => typeof fn === "function"; // 是否函数
A.add = (ls, v) => (ls[ls.length] = v); // 比push高效
A.remove = (ls, v) => {
  const idx = ls.indexOf(v);
  if (idx !== -1) ls.splice(idx, 1);
};

// 发布订阅
class Topic {
  static callTask(fn, args) {
    try { fn(args); } catch (e) { console.error(e); } // 同步调度(即时且隔离)
    // queueMicrotask(() => fn(args)); // 微任务调度(相对即时)
    // setTimeout(() => fn(args)); // 宏任务调度(非即时)
  }
  constructor(name) {
    Object.assign(this, { name, fns: [], once: [] });
  }
  sub(fn, once) {
    if (F.is(fn)) A.add(once ? this.once : this.fns, fn);
  }
  unsub(fn, once) {
    if (F.is(fn)) A.remove(once ? this.once : this.fns, fn);
  }
  pub(args) {
    const L0 = this.fns.slice(0);
    const L1 = this.once.splice(0); // 提取并置空原数组
    for (let i = 0, l = L0.length; i < l; i++) Topic.callTask(L0[i], args);
    for (let i = 0, l = L1.length; i < l; i++) Topic.callTask(L1[i], args);
  }
}

// 事件
class TBus {
  static sk = Symbol(TBus.name);
  static del = (bus, k) => bus[TBus.sk].delete(k); // 销毁Topic防止内存泄漏
  static get = (bus, k) => bus[TBus.sk].get(k) || bus[TBus.sk].set(k, new Topic(k)).get(k);
  constructor() {
    this[TBus.sk] = new Map(); // Map读写快、Object删改快
  }
  once(type, fn) {
    this.on(type, fn, true);
  }
  on(type, fn, once) {
    TBus.get(this, type).sub(fn, once); // 订阅
  }
  off(type, fn, once) {
    TBus.get(this, type).unsub(fn, once); // 退订
  }
  emit(type, args) {
    TBus.get(this, type).pub(args); // 发布
  }
}

export { Topic, TBus };
export default TBus;
